//============================================================================================
/**
 * @file	point_calc.c
 * @brief	ポケスロンポイント計算
 * @author	Nozomu Saito
 *
 * 外部公開関数:PTC_
 */
//============================================================================================
#define POINT_MAX		(200.0)
#define POINT_MAX_FOR_CATCH		(150.0)	//キャッチ競技用
#define SUB_BASE_POINT	(120.0)

#include "application/pokethlon_frame.h"
#include "point_calc.h"

typedef void (*CALC_FUNC)(RSLT_PTR inResultPtr, const u8 inEvtNo);
typedef u8 (*CALC_FUNC_CORE)(u16 inRecord);

static u8 FixPoint(float inPointF);
static float CatchDefaultCalcCore(u16 inRecord, const float inCoefficient );

static void CalcEvt(RSLT_PTR inResultPtr, const u8 inEvtNo );

static void CalcEvtOne(RSLT_PTR inResultPtr, const u8 inEvtNo );	//リザルトごと個別
static void CalcEvtAll(RSLT_PTR inResultPtr, const u8 inEvtNo );	//リザルトから一括

static void CalcEvtShot(RSLT_PTR inResultPtr);	//シュート

static u8 CalcEvtCoreA(u16 inRecord);	//ハードル
static u8 CalcEvtCoreB(u16 inRecord);	//フラッグ
static u8 CalcEvtCoreC(u16 inRecord);	//サークル
static u8 CalcEvtCoreD(u16 inRecord);	//カワラ
static u8 CalcEvtCoreE(u16 inRecord);	//キャッチ
static u8 CalcEvtCoreF(u16 inRecord);	//ジャンプ
static u8 CalcEvtCoreG(u16 inRecord);	//マラソン
static u8 CalcEvtCoreH(u16 inRecord);	//ドロップ
static u8 CalcEvtCoreI(u16 inRecord);	//スロー

const CALC_FUNC CalcFuncTbl[PKTHLN_EVT_MAX] = {
	CalcEvtOne,	//ハードル
	CalcEvtOne,	//フラッグ
	CalcEvtOne,	//サークル
	CalcEvtOne,	//カワラ
	CalcEvtOne,	//キャッチ
	CalcEvtOne,	//ジャンプ
	CalcEvtOne,	//マラソン
	CalcEvtOne,	//ドロップ
	CalcEvtOne,	//スロー
	CalcEvtAll,	//シュート
};

const CALC_FUNC_CORE CalcCoreFuncTbl[PKTHLN_EVT_MAX] = {
	CalcEvtCoreA,	//ハードル
	CalcEvtCoreB,	//フラッグ
	CalcEvtCoreC,	//サークル
	CalcEvtCoreD,	//カワラ
	CalcEvtCoreE,	//キャッチ
	CalcEvtCoreF,	//ジャンプ
	CalcEvtCoreG,	//マラソン
	CalcEvtCoreH,	//ドロップ
	CalcEvtCoreI,	//スロー
	NULL,	//シュート
};

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算
 *
 *	@param	inResultPtr		リザルトポインタ
 *	@param	inEvtNo			イベントナンバー
 *
 *	@return
 */
//-----------------------------------------------------------------------------
void PTC_CalcPoint(RSLT_PTR inResultPtr, const u8 inEvtNo)
{
	CalcFuncTbl[inEvtNo](inResultPtr, inEvtNo);
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算
 *
 *	@param	inResultPtr		リザルトポインタ
 *	@param	inEvtNo			イベントナンバー
 *
 *	@return
 */
//-----------------------------------------------------------------------------
static void CalcEvtOne(RSLT_PTR inResultPtr, const u8 inEvtNo )
{
	u8 i;
	if (CalcCoreFuncTbl[inEvtNo] != NULL){
		for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
			RESULT_DATA *data = RSLT_GetResultDataPtr(inResultPtr, i);
			data->Score = CalcCoreFuncTbl[inEvtNo](data->RecordOrg);
		}
	}else{
		GF_ASSERT(0);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算
 *
 *	@param	inResultPtr		リザルトポインタ
 *	@param	inEvtNo			イベントナンバー
 *
 *	@return
 */
//-----------------------------------------------------------------------------
static void CalcEvtAll(RSLT_PTR inResultPtr, const u8 inEvtNo )
{
	u8 i;
	if (CalcCoreFuncTbl[inEvtNo] == NULL){
		CalcEvtShot(inResultPtr);
	}else{
		GF_ASSERT(0);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	キャッチ少数得点計算（デフォルト）
 *
 *	@param	inRecord			記録
 *	@param	inCoefficient		係数
 *
 *	@return	point_f		少数得点
 */
//-----------------------------------------------------------------------------
static float CatchDefaultCalcCore(u16 inRecord, const float inCoefficient )
{
	float total_score;
	float point_f;
	total_score = (float)inRecord;
	point_f = POINT_MAX_FOR_CATCH - ( SUB_BASE_POINT / ((total_score*inCoefficient)+1.0) );
	return point_f;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算補正
 *
 *	@param	inPointF	小数点得点
 *
 *	@return	point		整数得点
 */
//-----------------------------------------------------------------------------
static u8 FixPoint(float inPointF)
{
	u8 point;
	u32 tmp;
	tmp = (u32)inPointF;
	if (tmp > POINT_MAX){
		tmp = POINT_MAX;
	}
	point = tmp;
	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（ハードル）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreA(u16 inRecord)
{
	u8 point;
	float total_score;
	float point_f;

	total_score = (float)inRecord;
	point_f = 11500.0 / (total_score/30);

	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（フラッグ）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreB(u16 inRecord)
{
	u8 point;
	float point_f;

//	point_f = DefaultCalcCore(inRecord, 0.08 );
	point_f = inRecord * 3;
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（サークル）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreC(u16 inRecord)
{
	u8 point;
	float point_f;

//	point_f = DefaultCalcCore(inRecord, 0.03 );
	point_f = inRecord * 3;
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（カワラ）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreD(u16 inRecord)
{
	u8 point;
	float point_f;

//	point_f = DefaultCalcCore(inRecord, 0.02 );
	point_f = inRecord;
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（キャッチ）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreE(u16 inRecord)
{
	u8 point;
	float point_f;

	point_f = CatchDefaultCalcCore(inRecord, 0.08 );
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（ジャンプ）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreF(u16 inRecord)
{
	u8 point;
	float point_f;

//	point_f = DefaultCalcCore(inRecord, 0.005 );
	point_f = inRecord;
	point_f /= 3.5;
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（マラソン）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreG(u16 inRecord)
{
	u8 point;
	float total_score;
	float point_f;

	total_score = (float)inRecord;
	point_f = (total_score/1024.0) * 10.0;		//１周1024

	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（ドロップ）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreH(u16 inRecord)
{
	u8 point;
	float point_f;

///	point_f = DefaultCalcCore(inRecord, 0.0175 );
	point_f = inRecord;
	point_f *= 1.5;
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（スロー）
 *
 *	@param	inRecord	記録
 *
 *	@return	point		得点
 */
//-----------------------------------------------------------------------------
static u8 CalcEvtCoreI(u16 inRecord)
{
	u8 point;
	float point_f;

//	point_f = DefaultCalcCore(inRecord, 0.06 );
	point_f = inRecord * 3;
	point = FixPoint(point_f);

	return point;
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点計算（シュート）
 *
 *	@param	inResultPtr	リザルトポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void CalcEvtShot(RSLT_PTR inResultPtr)
{
	u8 i,j;
	u8 rank_ary[ENTRY_MEMBER_NUM_MAX];
	u8 grade_ary[ENTRY_MEMBER_NUM_MAX];
	u8 base_point[ENTRY_MEMBER_NUM_MAX] = { 100, 80, 70, 60 };		//基準加算ポイント

	u8 plus = 0;
	u16 score;

	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		RESULT_DATA *data = RSLT_GetResultDataPtr(inResultPtr, i);
		//ランク配列
		rank_ary[i] = data->Rank;
		//評点配列初期化
		grade_ary[i] = 0;
	}

	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		u8 my_rank = rank_ary[i];
		RESULT_DATA *data = RSLT_GetResultDataPtr(inResultPtr, i);
		for(j=0;j<ENTRY_MEMBER_NUM_MAX;j++){
			if (i==j){
				continue;
			}
			//ランク別に点数を決める
			if (my_rank == rank_ary[j]){
				//評点を下げる(インクリメントで評点が下がる)
				grade_ary[i]++;
			}
		}

		//加算ポイント決定
		plus = base_point[ rank_ary[i]+grade_ary[i] ];

		score = (data->RecordOrg*5) + plus;
		if (score > POINT_MAX){
			score = (u16)POINT_MAX;
		}
		data->Score = score;
	};
}